package org.jflame.boot_samples.config;

import org.jflame.commons.util.DateHelper;
import org.jflame.web.spring.MyExceptionResolver;
import org.jflame.web.spring.inteceptor.LocaleAndTimeZoneChangeInterceptor;
import org.jflame.web.spring.jackson.JacksonFilter;
import org.jflame.web.spring.jackson.MyMappingJackson2HttpMessageConverter;

import java.util.List;
import java.util.Locale;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
// @EnableWebMvc //表示完全自己控制mvc配置，也就是说所有配置自己重写，所有默认配置都没了
public class MvcConfig implements WebMvcConfigurer {

    @Autowired
    WebMvcProperties mvcProperties;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleAndTimeZoneChangeInterceptor())
                .addPathPatterns("/**");
    }

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
        sessionLocaleResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return sessionLocaleResolver;
    }

    /**
     * 启用web容器defaultServlet,需要配置server.servlet.register-default-servlet=true
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    /**
     * 使用默认ObjectMapper自定义MappingJackson2HttpMessageConverter,支持接口处动态过滤输出属性
     * 
     * @see JacksonFilter
     * @param objectMapper
     * @return
     */
    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
        return new MyMappingJackson2HttpMessageConverter(objectMapper);
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // spring.mvc.format的配置只Local时间生效,拿配置的格式应用到Date
        /*
         * spring.mvc.format 配置三种格式对应localDateTime,localDate,localTime
         * 但对Date类型支持不完全,WebConversionService只用spring.mvc.format.date格式生成了一个对Date的DateFormatter
         * */
        String dateTimeFmt = mvcProperties.getFormat()
                .getDateTime();
        if (dateTimeFmt != null && dateTimeFmt.toLowerCase()
                .startsWith("iso")) {
            dateTimeFmt = DateHelper.YYYY_MM_DD_T_HH_mm_ss;
        }
        String dateFmt = mvcProperties.getFormat()
                .getDate();
        if (dateFmt != null && dateFmt.toLowerCase()
                .startsWith("iso")) {
            dateFmt = DateHelper.YYYY_MM_DD;
        }
        String timeFmt = mvcProperties.getFormat()
                .getTime();
        if (timeFmt != null && timeFmt.toLowerCase()
                .startsWith("iso")) {
            timeFmt = DateHelper.HH_mm_ss;
        }

        // 使用spring自带DateFormatter
        /*DateFormatter myDateFormatter = new DateFormatter(dateTimeFmt);
        myDateFormatter.setFallbackPatterns(DateHelper.LONG_PATTEN);
        registry.addFormatter(myDateFormatter);
        
        registry.addFormatterForFieldType(java.sql.Timestamp.class, myDateFormatter);
        
        DateFormatter mySqlDateFormatter = new DateFormatter(dateFmt);
        mySqlDateFormatter.setFallbackPatterns(DateHelper.SHORT_PATTEN);
        
        registry.addFormatterForFieldType(java.sql.Date.class, mySqlDateFormatter);
        DateFormatter mySqlTimeFormatter = new DateFormatter(timeFmt);
        registry.addFormatterForFieldType(java.sql.Time.class, mySqlTimeFormatter);
        // 添加Date转到java.sql时间子类的Converter,否则DateFormatter无法支持Date子类
        DateToSqlDateConverters.addConverter(registry);*/

        // 使用自定义DateFormatter
        /* new MyDateFormatter<>(Date.class, dateTimeFmt, true).fallbackPatterns(DateHelper.LONG_PATTEN)
                .register(registry);
        new MyDateFormatter<>(java.sql.Timestamp.class, dateTimeFmt).fallbackPatterns(DateHelper.LONG_PATTEN)
                .register(registry);
        new MyDateFormatter<>(java.sql.Date.class, dateFmt).fallbackPatterns(DateHelper.SHORT_PATTEN)
                .register(registry);
        new MyDateFormatter<>(java.sql.Time.class, timeFmt).register(registry);*/

        // TimestampStrToDateFormatter<Date> myDateFormatter = new TimestampStrToDateFormatter<>(java.util.Date.class);
        // registry.addFormatter(myDateFormatter);
    }

    @Bean
    public ServletListenerRegistrationBean<RequestContextListener> servletListenerRegistrationBean() {
        ServletListenerRegistrationBean<RequestContextListener> servletListener = new ServletListenerRegistrationBean<>();
        servletListener.setListener(new RequestContextListener());
        // servletListener.setOrder(servletListener.getOrder() - 1);

        return servletListener;
    }

    /*@Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource result = new ResourceBundleMessageSource();
        //ReloadableResourceBundleMessageSource result = new ReloadableResourceBundleMessageSource();
        //StaticMessageSource
        result.setBasenames("i18n/message"); 
        return result;
    }*/

    @Override
    public Validator getValidator() {
        return WebMvcConfigurer.super.getValidator();
    }

    @Bean
    @Primary
    public Validator validator(MessageSource messageSource) {
        // bean-validation与spring共用一个国际化语言文件
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        validator.setValidationMessageSource(messageSource);
        // validator.getValidationPropertyMap().put("hibernate.validator.fail_fast", "true");
        return validator;
    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        resolvers.add(0, new MyExceptionResolver());
    }

}
